package studio.xiaoyun.core.dao.impl;

import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;

import studio.xiaoyun.core.dao.IBaseDao;

/**
 * 定义一些通用的DAO层方法
 * @param <T> 实现该接口时需要指定具体的实体类
 * @param <V> 主键类型
 */
public abstract class BaseDao<T,V> implements IBaseDao<T,V> {

	@Resource
	private SessionFactory sessionFactory;

	@Override
	public void delete(T entity) {
		Session session = this.getSession();
		session.delete(entity);
	}
	
	@Override
	public void deleteByID(V ID){
		Session session = this.getSession();
		T t = this.loadByID(ID);
		session.delete(t);
	}
	
	/**
	 * 根据HQL语句查询数据
	 * @param hql hql语句
	 * @return 查询结果
	 */
	protected <F> List<F> getByHQL(String hql) {
		Session session = this.getSession();
		Query query = session.createQuery(hql);
		@SuppressWarnings("unchecked")
		List<F> list = query.list();
		return list;
	}

	/**
	 * 根据SQL语句查询数据，结果不是实体，是Object列表
	 * @param sql sql语句
	 * @return 查询结果
	 */
	protected List<Object> getBySQL(String sql) {
		Session session = this.getSession();
		SQLQuery query = session.createSQLQuery(sql);
		@SuppressWarnings("unchecked")
		List<Object> list = query.list();
		return list;
	}

	/**
	 * 根据sql语句取得实体
	 * @param <F> 实体的类型
	 * @param sql 完整的sql语句，需要有'*'号，例如：select alias.* from table as alias
	 * @param alias  sql语句中表的别名，例如：alias
	 * @param _class 实体的类型
	 * @return 实体列表
	 */
	protected <F> List<F> getBySQL(String sql, String alias, Class<F> _class) {
		Session session = this.getSession();
		SQLQuery query = session.createSQLQuery(sql);
		query.addEntity(alias, _class);
		@SuppressWarnings("unchecked")
		List<F> list = query.list();
		return list;
	}

	/**
	 * 根据detachedCriteria获得记录的总数
	 * @param detachedCriteria  DetachedCriteria的实例
	 * @return 记录总数
	 */
	protected long getCountByDetachedCriteria(final DetachedCriteria detachedCriteria) {
		Session session = this.getSession();
		Criteria c = detachedCriteria.getExecutableCriteria(session);
		long count = (Long) c.uniqueResult();
		return count;
	}

	/**
	 * 根据HQL语句查询数据的数量
	 * @param hql hql语句
	 * @return 数量
	 */
	protected long getCountByHQL(String hql) {
		Session session = this.getSession();
		Query query = session.createQuery(hql);
		long count = (Long) query.uniqueResult();
		return count;
	}

	/**
	 * 根据SQL语句查询数据的数量
	 * @param sql sql语句
	 * @return 数量
	 */
	protected long getCountBySQL(String sql) {
		Session session = this.getSession();
		SQLQuery query = session.createSQLQuery(sql);
		BigInteger count = (BigInteger) query.uniqueResult();
		return count.longValue();
	}

	/**
	 * 获得Criteria
	 * @param _class Class
	 * @return Criteria
	 */
	protected Criteria getCriteria(Class<?> _class) {
		Session session = this.getSession();
		return session.createCriteria(_class);
	}

	/**
	 * 获得当前事务中的session
	 * @return session
	 */
	protected Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public List<V> save(List<T> entitys) {
		List<V> result = new LinkedList<V>();
		Session session = this.getSession();
		for(int i=0;i<entitys.size();i++){
			@SuppressWarnings("unchecked")
			V id = (V)session.save(entitys.get(i));
			result.add(id);
			if(i % 50 == 0){
				session.flush();
				session.clear();
			}
		}
		return result;
	}
	
	@Override
	public V save(T entity) {
		Session session = this.getSession();
		@SuppressWarnings("unchecked")
		V ID = (V) session.save(entity);
		return ID;
	}
	
	@Override
	public void update(List<T> entitys) {
		Session session = this.getSession();
		for(int i=0;i<entitys.size();i++){
			session.update(entitys.get(i));
			if(i % 50 == 0){
				session.flush();
				session.clear();
			}
		}
	}

	@Override
	public void update(T entity) {
		Session session = this.getSession();
		session.update(entity);
	}

}